{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://en.cppreference.com/w/cpp/memory/polymorphic_allocator.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 C++11 之前，标准容器使用的分配器接口（`Allocator`）基于模板参数，类型耦合严重，尤其是对 **状态ful allocator**（保存内存池指针、线程局部数据等）的支持较为笨重。\n",
    " C++11 虽引入了移动语义、`scoped_allocator_adaptor` 等改进，但因 allocator 类型仍然是模板参数：\n",
    "\n",
    "- **容器类型与 allocator 类型强绑定**，跨模块/库共享分配器困难；\n",
    "- 运行期动态选择内存策略几乎不可能；\n",
    "- 若要切换 allocator，需要重新定义容器类型（如 `std::vector<T, CustomAllocator>`），影响泛型代码复用。\n",
    "\n",
    "为了在保留高性能特性的前提下提供 **运行期可切换的分配策略**，C++17 标准引入了 **`<memory_resource>` 头**，通常以 `std::pmr` 命名空间访问相关设施（`std::pmr` 是 `std::experimental::pmr` 的推广）。该方案在 C++11 之后的现代 C++ 内存定制需求中起到了核心作用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主要目标\n",
    "\n",
    "1. **运行期开关 allocator 策略（多态分配）**：通过类型擦除（type erasure）使不同 allocator 策略以统一接口呈现。\n",
    "2. **降低模板耦合**：容器实例与 allocator 策略解耦，使同一容器类型可根据运行期需求切换内存资源。\n",
    "3. **简化使用体验**：提供 `pmr::vector`、`pmr::string` 等别名，默认使用多态 allocators，便于快速替换。\n",
    "4. **提供标准内存资源实现**：如单调增长（`monotonic_buffer_resource`）与内存池（`unsynchronized_pool_resource`）等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 核心组件与实现原理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::pmr::memory_resource`: 类型擦除的抽象基类\n",
    "- **抽象基类 + 虚函数** 实现类型擦除，将分配/释放行为封装在派生类中。\n",
    "- `memory_resource` 对象常由指针（或引用）持有。在运行期，指向不同派生实现，即可切换策略。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "class memory_resource {\n",
    "public:\n",
    "    void* allocate(size_t bytes, size_t alignment = max_align);\n",
    "    void  deallocate(void* p, size_t bytes, size_t alignment = max_align);\n",
    "    bool  is_equal(const memory_resource& other) const noexcept;\n",
    "\n",
    "protected:\n",
    "    virtual void* do_allocate(size_t, size_t) = 0;\n",
    "    virtual void  do_deallocate(void*, size_t, size_t) = 0;\n",
    "    virtual bool  do_is_equal(const memory_resource&) const noexcept = 0;\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::pmr::polymorphic_allocator<T>`\n",
    "\n",
    "- 遵守标准 allocator 接口，实现上仅保存指向 `memory_resource` 的指针。\n",
    "- 所有分配/释放操作都委托给持有的 `memory_resource`。\n",
    "- 可在运行期构造时传入不同资源指针，即实现 **“同一容器类型，运行期选择 allocator”**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template<class T>\n",
    "class polymorphic_allocator {\n",
    "    memory_resource* resource_;\n",
    "public:\n",
    "    T* allocate(size_t n) {\n",
    "        return static_cast<T*>(resource_->allocate(n * sizeof(T), alignof(T)));\n",
    "    }\n",
    "    void deallocate(T* p, size_t n) {\n",
    "        resource_->deallocate(p, n * sizeof(T), alignof(T));\n",
    "    }\n",
    "    // ...\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pmr::vector`, `pmr::string` 等容器别名"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "namespace std::pmr {\n",
    "    template<class T>\n",
    "    using vector = std::vector<T, polymorphic_allocator<T>>;\n",
    "\n",
    "    using string = std::basic_string<char, std::char_traits<char>,\n",
    "                                     polymorphic_allocator<char>>;\n",
    "    // ... 以及 deque, list, map, unordered_map 等别名\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 使用这些别名即可“随手”获得多态 allocator 能力。例如：\n",
    "\n",
    "std::pmr::monotonic_buffer_resource pool{buffer, sizeof(buffer)};\n",
    "std::pmr::vector<int> vec{&pool};       // 运行期绑定具体资源\n",
    "vec.reserve(256);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "资源实例与生命周期管理\n",
    "\n",
    "- `pmr::get_default_resource()` / `pmr::set_default_resource()`<br>\n",
    "   管理全局默认资源，默认为 `new_delete_resource()`（使用全局 `operator new/delete`）。\n",
    "- `pmr::monotonic_buffer_resource`<br>\n",
    "   单调递增分配器，适合短生命周期或一次性构建后整体释放的场景（如 AST 构建、解析器）。\n",
    "- `pmr::unsynchronized_pool_resource` / `pmr::synchronized_pool_resource`<br>\n",
    "   提供小块内存池，减少频繁分配/释放带来的碎片和锁开销。\n",
    "- `pmr::null_memory_resource()`<br>\n",
    "   永远分配失败，可用于捕捉越界/非法分配。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "标准实现策略（示意）\n",
    "\n",
    "- `monotonic_buffer_resource`：维护当前指针与剩余空间，无回收；缓冲区耗尽时向上游资源申请更大块内存。\n",
    "- `unsynchronized_pool_resource`：按块大小管理多个池，每个池维护空闲链表；访问不加锁，需外部保证线程安全。\n",
    "- `synchronized_pool_resource`：在 `unsynchronized` 基础上增加互斥锁或原子操作，线程安全但有锁竞争。\n",
    "\n",
    "这些资源类都有一个“上游资源（upstream resource）”的概念，形成链式组合。最终最顶层通常以 `new_delete_resource()` 结束（即普通堆分配）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实际应用场景\n",
    "\n",
    "1. **短期对象批量创建**<br/>\n",
    "    使用 `monotonic_buffer_resource` 可实现近似栈分配的 O(1) 构造成本，整体释放时间固定。\n",
    "2. **高频小对象分配**<br/>\n",
    "    `pool_resource` 减少碎片和锁竞争，适合日志系统、网络缓冲、游戏对象管理等。\n",
    "3. **模块化/插件系统**<br/>\n",
    "    插件可在运行期注入自定义 `memory_resource`，主程序无需重新定义容器类型。\n",
    "4. **自定义检测/统计**<br/>\n",
    "    继承 `memory_resource` 实现统计、限额、调试等功能，方便插拔。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 与传统 allocator 的对比\n",
    "\n",
    "| 方案                              | 特点                                                         | 适用场景                              |\n",
    "| --------------------------------- | ------------------------------------------------------------ | ------------------------------------- |\n",
    "| 模板型 allocator                  | 编译期绑定类型；类型安全、零运行期开销；切换策略需改模板参数 | 低层基础设施，需要极致性能时仍使用    |\n",
    "| `std::pmr::polymorphic_allocator` | 运行期可切换资源；通过虚函数实现类型擦除；容器类型稳定；适度额外开销（虚调用等） | 通用应用、框架/库暴露 API、插件系统等 |\n",
    "| 自定义内存池 + 手写接口           | 完全控制；但难以复用到标准容器；需要大量手工工作、易出错     | 极端性能要求或特殊结构                |\n",
    "\n",
    "> 由于 `pmr` 的虚函数调用与状态成员指针都很轻量，在多数场景中性能损耗可忽略，并可通过合理的资源实现获得更好的整体性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 小结\n",
    "\n",
    "- `std::pmr` 始于 C++17（C++11 之后的标准），提供了 **运行时多态的内存资源管理框架**。\n",
    "- 核心理念：通过 `memory_resource` + `polymorphic_allocator` **解耦容器类型与分配策略**，补足传统 allocator 在状态管理上的不足。\n",
    "- 标准库提供多种常用资源实现，并允许用户自定义，实现组合与叠加的灵活性。\n",
    "- `pmr::` 容器别名让在标准容器中使用多态分配器更简单，成为现代 C++ 内存调优的重要工具之一。\n",
    "\n",
    "掌握并结合 `pmr` 的原理与实践，可以在安全前提下实现高性能、可扩展、可调试的内存管理方案。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对于自定义类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **完全支持自定义类**：只需在类内使用 `pmr` 容器或 `polymorphic_allocator`，即可享受运行期可配置的内存资源。\n",
    "- **灵活组合**：类的用户可在构造对象时注入不同的 `memory_resource`，实现内存策略的动态切换。\n",
    "- **扩展能力强**：通过自定义内存资源，可实现计数、限额、调试、线程隔离等高级需求。\n",
    "\n",
    "因此，在现代 C++（C++17 及以后）中，`std::pmr` 是实现 **可插拔内存管理** 的重要工具，适用于标准容器和你自己的类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 在自定义类的成员中使用 `pmr` 对象\n",
    "\n",
    "如果类内部需要动态内存，例如 `std::string`、`std::vector`，可以改用对应的 `pmr` 版本，让这些成员的内存来源于指定的 `memory_resource`。\n",
    "- 成员 `message_`、`metadata_` 分别是 `pmr::string`、`pmr::vector`，它们都会使用传入的 `memory_resource`。\n",
    "- 类可以提供一个构造函数，接受 `memory_resource*`（带默认值），调用者就能在运行期指定内存策略。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <memory_resource>\n",
    "#include <vector>\n",
    "#include <string>\n",
    "\n",
    "class LogEntry {\n",
    "public:\n",
    "    using string   = std::pmr::string;\n",
    "    using metadata = std::pmr::vector<std::pmr::string>;\n",
    "\n",
    "    LogEntry(std::pmr::memory_resource* res = std::pmr::get_default_resource())\n",
    "        : message_(res)\n",
    "        , metadata_(res) {}\n",
    "\n",
    "    void set_message(std::string_view msg) {\n",
    "        message_.assign(msg.begin(), msg.end());\n",
    "    }\n",
    "\n",
    "    void add_tag(std::string_view tag) {\n",
    "        metadata_.emplace_back(tag.begin(), tag.end());\n",
    "    }\n",
    "\n",
    "private:\n",
    "    string   message_;\n",
    "    metadata metadata_;\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 自定义类型的容器也可受益\n",
    "\n",
    "无论是标准容器还是你自定义的容器，只要它支持传入 `Allocator`，就可以直接使用 `std::pmr::polymorphic_allocator<T>`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template<class T>\n",
    "class MyPoolBackedList {\n",
    "public:\n",
    "    using allocator_type = std::pmr::polymorphic_allocator<T>;\n",
    "\n",
    "    explicit MyPoolBackedList(std::pmr::memory_resource* res\n",
    "                              = std::pmr::get_default_resource())\n",
    "        : alloc_(res) {}\n",
    "\n",
    "    void push(const T& value) {\n",
    "        // 假设你有自己的节点管理，这里使用 alloc_ 进行分配\n",
    "        Node* node = alloc_.allocate(1);\n",
    "        alloc_.construct(node, value);\n",
    "        node->next = head_;\n",
    "        head_ = node;\n",
    "    }\n",
    "\n",
    "    // ... 其他操作 ...\n",
    "\n",
    "private:\n",
    "    struct Node {\n",
    "        T     value;\n",
    "        Node* next;\n",
    "    };\n",
    "\n",
    "    allocator_type alloc_;\n",
    "    Node*          head_ = nullptr;\n",
    "};\n",
    "\n",
    "// 使用方式\n",
    "\n",
    "std::byte buffer[1024];\n",
    "std::pmr::monotonic_buffer_resource pool{buffer, sizeof(buffer)};\n",
    "\n",
    "MyPoolBackedList<int> list{&pool};\n",
    "list.push(1);\n",
    "list.push(2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 自定义 `memory_resource`\n",
    "\n",
    "如果你需要特殊的内存管理（统计、限额、调试等），可以继承 `std::pmr::memory_resource`，并在自定义类中使用这类资源。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "class counting_resource : public std::pmr::memory_resource {\n",
    "public:\n",
    "    explicit counting_resource(std::pmr::memory_resource* upstream\n",
    "                               = std::pmr::get_default_resource())\n",
    "        : upstream_(upstream) {}\n",
    "\n",
    "    std::size_t bytes_allocated() const noexcept { return bytes_allocated_; }\n",
    "\n",
    "protected:\n",
    "    void* do_allocate(std::size_t bytes, std::size_t alignment) override {\n",
    "        bytes_allocated_ += bytes;\n",
    "        return upstream_->allocate(bytes, alignment);\n",
    "    }\n",
    "\n",
    "    void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {\n",
    "        bytes_allocated_ -= bytes;\n",
    "        upstream_->deallocate(p, bytes, alignment);\n",
    "    }\n",
    "\n",
    "    bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {\n",
    "        return this == &other;\n",
    "    }\n",
    "\n",
    "private:\n",
    "    std::pmr::memory_resource* upstream_;\n",
    "    std::size_t                bytes_allocated_ = 0;\n",
    "};\n",
    "\n",
    "// 使用\n",
    "counting_resource counter;\n",
    "LogEntry entry{&counter};\n",
    "entry.set_message(\"hello pmr\");\n",
    "entry.add_tag(\"info\");\n",
    "// 此时 counter.bytes_allocated() 可查看消耗的字节数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 自定义类型中的生命周期约定\n",
    "\n",
    "当你的类型持有 `memory_resource*` 时，请确保：\n",
    "\n",
    "1. 传入的 `memory_resource` 在对象生命周期内保持有效；\n",
    "2. 如果类型需要复制/移动，需要决定是否共享同一资源或允许调用者指定新资源；\n",
    "3. 必要时提供带资源参数的复制构造/赋值重载，以便用户控制内存策略。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "class LogEntry {\n",
    "public:\n",
    "    // ...\n",
    "    LogEntry(const LogEntry& other, std::pmr::memory_resource* res)\n",
    "        : message_(other.message_, res)\n",
    "        , metadata_(other.metadata_, res) {}\n",
    "\n",
    "    // 允许调用者用新资源复制\n",
    "    LogEntry copy_with_resource(std::pmr::memory_resource* res) const {\n",
    "        return LogEntry(*this, res);\n",
    "    }\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# “`pmr` vs 自定义内存池”\n",
    "\n",
    "| 维度                      | `pmr` 标准资源                               | 自定义内存池                                             |\n",
    "| ------------------------- | -------------------------------------------- | -------------------------------------------------------- |\n",
    "| 抽象层级                  | 提供原始内存（`void*`），不涉及对象构造/复用 | 可管理对象生命周期、状态重置、统计、监控                 |\n",
    "| 线程安全                  | `unsynchronized` 不加锁；`synchronized` 加锁 | 你可完全控制锁策略、线程绑定、Cache 亲和性               |\n",
    "| 内存来源                  | 默认向 `new/delete` 请求；可指定上游资源     | 可来自预分配静态区、共享内存、DMA、特殊硬件地址          |\n",
    "| 粒度控制                  | 标准池针对小块优化，策略固定                 | 可基于块大小、对象类型定制；支持 slab、bitmap 等复杂机制 |\n",
    "| 泄漏检测/限额             | 需自行封装                                   | 可内建统计、阈值报警                                     |\n",
    "| 对象重用（placement new） | 需额外封装                                   | 通常自带 `acquire/release` 接口                          |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`pmr` 如何与内存池协作？**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "直接使用标准资源\n",
    "- 如果需求是简单的“小块对象高频分配”“一批对象一次释放”："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "std::pmr::monotonic_buffer_resource arena(buffer, sizeof(buffer));\n",
    "std::pmr::vector<MyStruct> data{&arena};  // 零动态分配\n",
    "\n",
    "std::pmr::unsynchronized_pool_resource pool;\n",
    "std::pmr::unordered_map<Key, Value> cache{&pool}; // 使用标准内存池"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将自定义内存池包装成 `memory_resource`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "class my_pool_resource : public std::pmr::memory_resource {\n",
    "public:\n",
    "    explicit my_pool_resource(ObjectPool& pool) : pool_(pool) {}\n",
    "\n",
    "private:\n",
    "    void* do_allocate(std::size_t bytes, std::size_t alignment) override {\n",
    "        return pool_.allocate(bytes, alignment);\n",
    "    }\n",
    "    void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {\n",
    "        pool_.deallocate(p, bytes, alignment);\n",
    "    }\n",
    "    bool do_is_equal(const memory_resource& other) const noexcept override {\n",
    "        return this == &other;\n",
    "    }\n",
    "\n",
    "    ObjectPool& pool_;\n",
    "};\n",
    "\n",
    "// 使用时直接传入：\n",
    "ObjectPool pool{/*...*/};\n",
    "my_pool_resource res{pool};\n",
    "std::pmr::vector<MyStruct> vec{&res};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "什么时候 `pmr` 不够？\n",
    "- **要管理对象状态**（构造、析构、reset）时，`pmr` 只能提供裸内存，无法代替对象池（Object Pool）。\n",
    "- **需要严格的实时或硬件绑定内存策略**（如特定内存段、DMA、NUMA 亲和性），通常仍需自建池。\n",
    "- **要做复杂的占用统计、限额控制、泄漏检测**，`pmr` 得靠自定义派生类实现；标准资源无法满足。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实践建议\n",
    "\n",
    "1. **优先尝试 `pmr` 的标准资源**：若它们满足需求，可省去维护自定义池的复杂性。\n",
    "2. **已有内存池？包装成 `memory_resource`**：你能在不改容器模板参数的情况下接入运行时策略。\n",
    "3. **对象重用 ≠ 内存资源**：若需要复用对象（非仅内存），仍应使用对象池模式，`pmr` 可作为底层内存供给。\n",
    "4. **嵌入式/自动驾驶等高性能领域**：可用 `pmr` 统一抽象，同时保证“预分配 + 无动态堆”，兼顾灵活与安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "`std::pmr` **不能直接替代所有内存池**，但它提供了一个标准化、可组合的接口：\n",
    "\n",
    "- **简单需求** → 用 `pmr` 自带池即可；\n",
    "- **复杂需求** → 继续实现自定义内存池，并通过 `memory_resource` 接入，享受 `pmr` 带来的容器一致性与运行时灵活性。\n",
    "\n",
    "换言之，`pmr` 更像是“把内存池纳入 STL 优雅体系”的桥梁，而不是“彻底告别自定义内存池”的替代品。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
